/* Copyright 2001,2002,2003 NAH6
 * All Rights Reserved
 *
 * Parts Copyright DoD, Parts Copyright Starium
 *
 */
          /*LINTLIBRARY*/
          /*PROTOLIB1*/

#include "main.h"
#include <math.h>
#include "con_adap.h"
#include "con_stch.h"
#include "interp.h"
#include "lp_syn.h"
#include "movarray.h"
#include "postfilt.h"
#include "setarray.h"
#include "synth.h"
#include "filter.h"


static void SquelchTest(
int	len,
int	frame_num,
float	speech[]);

static int clip(
float 	s[],
int 	l);

/**************************************************************************
*                                                                         *
* ROUTINE
*		Synthesis
*
* FUNCTION
*		CELP synthesis
* SYNOPSIS
*		Synthesis(parameters, BitIntegrity, frame_num, speech_out)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*	parameters	TX_PARAM i	Frame of CELP parameters
*	BitIntegrity	INTEGRITY i	Integrity of decoded bitstream (future)
*	frame_num	int	 i	Frame number
*	speech_out	float	 o	Frame of output speech
*
**************************************************************************/
void Synthesis(
TX_PARAM 	parameters,
int		frame_num,
float		speech_out[F_LEN])
{
float 		lsfint[NUM_SF][ORDER];
float		excitation[SF_LEN];
static float	adapt_cw[ACB_SIZE];
float		lpc_speech[SF_LEN], post_speech[SF_LEN];
int		sf;
static int	first=TRUE;

/*  Initialize */
	if (first)	{
	  first = FALSE;
	  SetArray(ACB_SIZE, 0.0, adapt_cw);
	}

/*  Interpolate NUM_SF subframes of LSFs for subframe synthesis */
	Interpolate(parameters.lsf, lsfint, SYNTHESIS, frame_num);

/*  Synthesisze speech on a subframe basis */
	for (sf = 0; sf < NUM_SF; sf++) {

/*  Construct the stochastic codeword (initial excitation) */
	  ConstructStochCW(parameters.StochasticIndex[sf], 
		parameters.StochasticGain[sf], excitation);

/*  Construct the adaptive codeword and update excitation */
	  ConstructAdaptCW(excitation, SF_LEN, adapt_cw, ACB_SIZE, 
		parameters.AdaptiveGain[sf], parameters.AdaptiveDelay[sf], 
		"long");


/*  Perform LP excitation to produce speech */
	  LP_Synthesis(excitation, lsfint[sf], frame_num, lpc_speech);

/*  Apply post filter to lpc-speech */
	  PostFilter(lpc_speech, lsfint[sf], frame_num, post_speech);

/*  Test for clipping */
	  SquelchTest(SF_LEN, frame_num, post_speech);

#ifndef STREAMLINE
/*  Apply high pass filter to speech */
	  HPF_OutSpeech(post_speech, &speech_out[sf*SF_LEN]);
#else
/*  Copy postfiltered speech to output buffer */
	  MoveArray(SF_LEN, post_speech, &speech_out[sf*SF_LEN]);
#endif

	}


}
/*

*************************************************************************
*                                                                         *
* ROUTINE
*		SquelchTest
*
* FUNCTION
*		Test for clipping on input speech
* SYNOPSIS
*		SquelchTest(len, frame_num, speech)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*	len		int	 i	Length of speech buffer
*	frame_num	int	 i	Frame Number
*	speech_out	float	i/o	Frame of speech
*
**************************************************************************/

void SquelchTest(
int	len,
int	frame_num,
float	speech[])
{
int	i;

	while (clip(speech, len))	{
	  printf("celp: Clipping detected at frame %d\n", frame_num);
	  for(i=0;i<len;i++)
	    speech[i] = 0.05 * speech[i];
	}


}

/*

*************************************************************************
*
* ROUTINE
*               clip
*
* FUNCTION
*		Determine if speech is clipped
*
* SYnoPSIS
*               clip(s, l)
*
*   formal 
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*	s		float	i	input speech
*	l		int	i	length of input speech
*
***************************************************************************
*
* CALLED BY
*
*	celp
*
**************************************************************************/

int clip(
float 	s[],
int 	l)
{
  int i, count;
  float sum;

  /*	Count number of clippings and sum their magnitudes		*/

  count = 0;
  sum = 0.0;
  for (i = 0; i < l; i++)
  {
    if (fabs(s[i]) > 32768.0)
    {
      count++;
      sum += fabs(s[i]);
    }
  }

  /*	Clipping heuristics (could also use energy, delta energy, etc.)	*/

  return(((count >= 10) || (count >= 5 && sum > 1.e6)) ? TRUE : FALSE);
}
